/*
 * Events Class
 * 
 * 
 */

package controllers;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import models.*;
import notifiers.Mails;
import play.mvc.Controller;
import play.mvc.With;

import play.libs.Mail;

@With(Secure.class)
public class Events extends Controller {

	public static void index(long eventId) {

		Event event = Event.find("byId", eventId).first();
		render(event);

	}

	/**
	 * This method takes as a parameter the event id, the user id and the type
	 * of the board and it changes the attendance of the user in this meeting to
	 * be true if the component id was -1 then this is a project Board
	 * 
	 * @param userId
	 *            current user
	 * @param eventId
	 *            current event
	 * @param type
	 *            board type
	 * @param compId
	 *            component id
	 */
	public static void markAttendant(long userId, long eventId, String type,
			long compId) {
		Event event = Event.findById(eventId);
		User user = User.findById(userId);
		List<Event> meetings = new ArrayList<Event>();
		meetings = checkForMeeting(event.sprint);
		if (meetings.contains(event)) {
			EventUser eventUser = EventUser.find(
					"select eu from EventUser eu "
							+ "where eu.event=? and eu.user=?", event, user)
					.first();
			eventUser.attendance = true;
			eventUser.save();
			Log log = new Log(userId, eventId, "meeting", "attended", "")
					.save();
		} else {
			flash
					.error("sorry the meeting is over, your attendance was not taken");
		}
		if (compId == -1)
			Board.viewBoard((Long)event.getEntityId());
		else
			Board.viewComponentBoard((Long)event.getEntityId(), compId);
	}

	/**
	 * this method checks which meeting corresponds to the currently previewing
	 * user
	 * 
	 * @param List
	 *            list of current Meetings
	 * @return Event
	 */
	public static Event currMeeting(List<Event> currentMeetings) {
		for (int i = 0; i < currentMeetings.size(); i++) {
			List<User> attend = getAssignedUsers(currentMeetings.get(i)).get(0);
			List<User> abs = getAssignedUsers(currentMeetings.get(i)).get(1);
			attend.addAll(abs);
			for (int j = 0; j < attend.size(); j++) {
				if (Long.parseLong(session.get("userId")) == (Long) attend.get(
						j).getEntityId())
					return currentMeetings.get(i);
			}
		}
		return null;
	}

	/**
	 * this method get all the assigned users of the event (absent and
	 * attendant)
	 * 
	 * @param event
	 *            current event
	 * @return List<List<User>> :the first list is for the attending users and
	 *         the second one is for the absent users
	 */
	public static List<List<User>> getAssignedUsers(Event event) {
		List<EventUser> attendingUsers = EventUser.find(
				"select eu from EventUser eu "
						+ "where eu.event=? and attendance=?", event, true)
				.fetch();
		List<EventUser> absentUsers = EventUser.find(
				"select eu from EventUser eu "
						+ "where eu.event=? and attendance=?", event, false)
				.fetch();
		List<List<User>> result = new ArrayList<List<User>>();
		List<User> attending = new ArrayList<User>();
		List<User> absent = new ArrayList<User>();
		for (int i = 0; i < attendingUsers.size(); i++)
			attending.add(attendingUsers.get(i).user);
		for (int i = 0; i < absentUsers.size(); i++)
			absent.add(absentUsers.get(i).user);
		result.add(attending);
		result.add(absent);
		return result;
	}

	/**
	 * this method checks whether there is a meeting at this instance or not
	 * 
	 * @param event
	 *            current event
	 * @return list of currently held meetings
	 */
	public static List<Event> checkForMeeting(Event event) {
		Calendar cal = Calendar.getInstance();
		List<Event> meetings = event.events;
		for (int i = 0; i < meetings.size(); i++) {
			if (meetings.get(i).startDate.after(cal)
					|| meetings.get(i).endDate.before(cal)
					|| meetings.get(i).status == false) {
				meetings.remove(i);
				i--;
			}
		}
		meetings.add(event);
		return meetings;
	}

	public static void Requests(long projectId) {

		Project project = Project.find("byId", projectId).first();
		if (project == null)
			forbidden();
		Security.checkAccess("accept and reject Meeting request", projectId,
				Project.class.getName());

		LinkedList<Event> list = listMeetingRequests(projectId);
		render(project, list);
	}

	public static void createEvent(long projectId) {
		Project project = Project.findById(projectId);
		List<EventType> types = EventType.find("type!='Default'").fetch();
		List<Event> sprints = project.getSprints();
		render(sprints, project, types);
	}

	public static void createEventResponse(String name, String description,
			long type, String location, String strtDay, String strtMonth,
			String strtYear, String strtHour, String strtMin, String endDay,
			String endMonth, String endYear, String endHour, String endMin,
			long associatedID, boolean associateToProject) {

		GregorianCalendar startDate = new GregorianCalendar(Integer
				.parseInt(strtYear), Integer.parseInt(strtMonth), Integer
				.parseInt(strtDay), Integer.parseInt(strtHour), Integer
				.parseInt(strtMin));
		GregorianCalendar endDate = new GregorianCalendar(Integer
				.parseInt(endYear), Integer.parseInt(endMonth), Integer
				.parseInt(endDay), Integer.parseInt(endHour), Integer
				.parseInt(endMin));

		long userId = Long.parseLong(session.get("userId"));

		Event e = Event.createEvent(name, description, type, location,
				startDate, endDate, associatedID, associateToProject, userId);

		render(e);
	}

	/**
	 * Lists the requests of Meetings for a specific project
	 * 
	 * @param projectId
	 *            The id of the project
	 * 
	 */
	public static LinkedList<Event> listMeetingRequests(long projectId) {

		LinkedList<Event> requestList = new LinkedList();
		List<Event> event = Event.find("byStatus", false).fetch();
		for (int i = 0; i < event.size(); i++)
			try {
				if (event.get(i).project.id == projectId
						&& (!event.get(i).type.type.equals("Sprint"))
						&& (!event.get(i).type.type.equals("Default")))
					requestList.add(event.get(i));
			} catch (NullPointerException e) {
			}
		;
		Project project = Project.find("byId", projectId).first();
		// render(requestList, project);
		return (requestList);
	}

	/**
	 * Accepts a request of a meeting
	 * 
	 * @param EventId
	 *            The id of the meeting
	 */
	public static void AcceptRequest(long EventId) {

		Event event = Event.find("byId", EventId).first();
		if (event == null)
			forbidden("NO SUCH MEETING EXISTS");

		Security.checkAccess("accept and reject Meeting request", EventId,
				Event.class.getName());
		event.status = true;
		event.save();
		flash.success(event.name + " has been accepted");
		// new Notification(event.user.id, event.name + " Request", event.name
		// + " request has been accepted by scrum master").save();
		// new Log(event.user.id, (Long) event.getEntityId(), Event.class
		// .getName(), "the following event request has been accepted: "
		// + event.name + " :\nmsg", (Long) event.project.getEntityId(),
		// "").save();
		Requests(event.project.id);
	}

	/**
	 * Reject a request of a meeting
	 * 
	 * @param EventId
	 *            The id of the meeting
	 */
	public static void RejectRequest(long EventId) {

		Security.checkAccess("accept and reject Meeting request", EventId,
				Event.class.getName());

		Event event = Event.find("byId", EventId).first();
		if (event == null)
			forbidden("NO SUCH MEETING EXISTS");

		Security.checkAccess("accept and reject Meeting request", EventId,
				Event.class.getName());

		event.delete();
		flash.success(event.name + " has been rejected");
		// new Notification(event.user.id, event.name + " Request", event.name
		// + " request has been rejected by scrum master").save();
		// new Log(event.user.id, (Long) event.getEntityId(), Event.class
		// .getName(), "the following event request has been rejected :"
		// + event.name + " :\nmsg", (Long) event.project.getEntityId(),
		// "").save();
		Requests(event.project.id);
	}

	/**
	 * Get the meeting types in a specific project
	 * 
	 * @param ProjectId
	 *            The id of the project
	 */
	public static LinkedList<String> getAllMeetingTypes(long ProjectId) {
		LinkedList<String> allTypes = new LinkedList();
		List<Event> all = Event.findAll();
		for (int i = 0; i < all.size() - 1; i++)
			if (!all.get(i).type.type.equals("Sprint"))
				allTypes.add(all.get(i).type.type);
		return allTypes;
	}

	public static List<Note> getNotesByEventID(long eventID) {
		Event e = Event.findById(eventID);
		return e.notes;
	}

	public static boolean checkTypeReview(long eventID) {
		Event e = Event.findById(eventID);
		return (e.type.type == "Review Meeting") ? true : false;
	}

	/**
	 * Lists all the available current events for a specific project
	 * 
	 * @param projectId
	 *            the required project
	 * @author Adam El Shafei
	 */

	public static List<Event> listAvailableEvents(long projectId) {
		Project p = Project.findById(projectId);
		List<Event> events = new LinkedList<Event>();
		for (int i = 0; i < p.events.size(); i++) {
			if (notPastEvent((Long) p.events.get(i).getEntityId()))
				events.add(p.events.get(i));
		}
		return events;
	}

	/**
	 * Checks which events have been completed
	 * 
	 * @param EventId
	 *            needed to be checked
	 * @author Adam El Shafei
	 */
	public static boolean notPastEvent(long eventId) {
		Event event = Event.findById(eventId);
		Calendar date = Calendar.getInstance();
		if (date.before(event.endDate)) {
			return true;
		}
		return false;
	}

	/**
	 * Removes a specific sprint
	 * 
	 * @param eventId
	 *            the required sprint to be deleted
	 * @author Adam El Shafei
	 */
	public static void removeSprint(long eventId) {
		Security.checkAccess("Remove a sprint from a project", eventId,
				Event.class.getName());
		Event sprint = Event.findById(eventId);
		Calendar now = Calendar.getInstance();
		List<Event> events = sprint.events;
		for (Event event : events)
			if (event.endDate.after(now)) {
				flash
						.error("cannot delete because theres an event in progress");
				showSprints((Long) sprint.project.getEntityId());
				// redirect("http://localhost:9000/events/showsprints?projectId="
				// + event.project.id);
			}
		sprint.delete();
		showSprints((Long) sprint.project.getEntityId());
		// redirect("http://localhost:9000/events/showsprints?projectId="
		// + event.project.id);
		// Get users in the sprint and notifies them
		List<User> users = EventUser.find(
				"select eu.user from EventUser eu where eu.event=?", sprint)
				.fetch();
		long projectId = (Long) sprint.project.getEntityId();
		Notifications.notifyAllUsers(users, "Sprint deleted", "Sprint "
				+ sprint.name + " is deleted");
		long userId = Long.parseLong(session.get("userId"));
		// Log
		new Log(userId, (Long) sprint.getEntityId(), Event.class.getName(),
				"Sprint " + sprint.name + " is deleted", projectId, "").save();
	}

	/**
	 * Creates an event and associates it with the Sprint event type, and the
	 * project in question.
	 * 
	 * @param projectId
	 *            the project with which to associate
	 * @param description
	 *            the Sprint description/goal
	 * @param startDate
	 *            the startDate
	 * @param endDate
	 *            the endDate
	 */
	public static void createSprint(long projectId, String name,
			String description, String startDate, String endDate) {
		Project project = Project.findById(projectId);
		EventType type = EventType.find("byType", "Sprint").first();
		Event sprint = new Event();
		String[] selectedStartDate = startDate.split("-");
		if (isValidDate(selectedStartDate)) {
			if (name.trim().isEmpty()) {
				flash.error("Sprint name can not be empty");
				createSprintForm(projectId);
			}
			sprint.name = name;
			sprint.description = description;
			String[] selectedEndDate = endDate.split("-");
			if (isValidDate(selectedEndDate)) {
				GregorianCalendar sDate = new GregorianCalendar(Integer
						.parseInt(selectedStartDate[2]), Integer
						.parseInt(selectedStartDate[1]) - 1, Integer
						.parseInt(selectedStartDate[0]));
				GregorianCalendar eDate = new GregorianCalendar(Integer
						.parseInt(selectedEndDate[2]), Integer
						.parseInt(selectedEndDate[1]) - 1, Integer
						.parseInt(selectedEndDate[0]));
				if (sDate.before(eDate)) {
					sprint.project = project;
					sprint.duration = new GregorianCalendar(0, 0, 0);
					sprint.duration.set(Calendar.DATE,
							project.defaultSprintDuration);
					sprint.startDate = sDate;
					sprint.endDate = eDate;
					sprint.duration = new GregorianCalendar(Integer
							.parseInt(selectedEndDate[2]), Integer
							.parseInt(selectedEndDate[1]) - 1, Integer
							.parseInt(selectedEndDate[0]));
					sprint.duration.add(Calendar.YEAR, Integer
							.parseInt(selectedStartDate[2])
							* -1);
					sprint.duration.add(Calendar.MONTH, Integer
							.parseInt(selectedStartDate[1])
							* -1);
					sprint.duration.add(Calendar.DATE, Integer
							.parseInt(selectedStartDate[0])
							* -1);
					sprint.type = type;
					type.events.add(sprint);
					sprint.save();
					flash.success("Sprint Created!");
					showSprints(projectId);
				} else {
					sprint.duration = new GregorianCalendar(0, 0, 0);
					sprint.duration.set(Calendar.DATE,
							project.defaultSprintDuration);
					sprint.startDate = sDate;
					sprint.endDate = new GregorianCalendar(Integer
							.parseInt(selectedStartDate[2]), Integer
							.parseInt(selectedStartDate[1]) - 1, Integer
							.parseInt(selectedStartDate[0]));
					sprint.endDate.add(Calendar.DATE,
							project.defaultSprintDuration);
				}
			} else {
				sprint.duration = new GregorianCalendar(0, 0, 0);
				sprint.duration.set(Calendar.DATE,
						project.defaultSprintDuration);
				sprint.startDate = new GregorianCalendar(Integer
						.parseInt(selectedStartDate[2]), Integer
						.parseInt(selectedStartDate[1]) - 1, Integer
						.parseInt(selectedStartDate[0]));
				sprint.endDate = new GregorianCalendar(Integer
						.parseInt(selectedStartDate[2]), Integer
						.parseInt(selectedStartDate[1]) - 1, Integer
						.parseInt(selectedStartDate[0]));
				sprint.endDate
						.add(Calendar.DATE, project.defaultSprintDuration);
			}
		} else {
			flash.error("Invalid Start Date");
			showSprints(projectId);
		}
	}

	/**
	 * Calls render to show the form required to create sprint, which in turn
	 * calls createSprint
	 * 
	 * @param projectId
	 *            the ID of the project to which this sprint is added
	 * 
	 */
	public static void createSprintForm(long projectId) {
		Project project = Project.findById(projectId);
		render(project);
	}

	/**
	 * Returns a list of all events in an arbitrary project having the specified
	 * type
	 * 
	 * @param eventType
	 *            The type of the events to be listed
	 * @param projectID
	 *            The ID of the project that contains the events
	 * @return A list of all events with the specified eventType and projectID
	 */
	public static List<Event> getEvents(String eventType, long projectID) {
		Project p = Project.findById(projectID);
		EventType et = EventType.find("byType", eventType).first();
		return getEvents(et, p);
	}

	/**
	 * Returns a list of all events in an arbitrary project having the specified
	 * type
	 * 
	 * @param eventType
	 *            The type of events to be listed
	 * @param project
	 *            The project to be searched for events of the specified type
	 * 
	 * @return A list of all events with the specified eventType in project
	 */
	public static List<Event> getEvents(EventType eventType, Project project) {
		List<Event> eventsOfType = Event.find("byType", eventType).fetch();
		List<Event> eventsOfTypeInProject = new LinkedList<Event>();
		for (Event anEvent : eventsOfType) {
			if (anEvent.project == project)
				eventsOfTypeInProject.add(anEvent);
		}
		return eventsOfTypeInProject;
	}

	/**
	 * Returns all the stories with a certain status in an event
	 * 
	 * @param eventId
	 *            the the event id
	 * @param status
	 *            the status of the story
	 * @return List<UserStory> a list of user stories in this event with this
	 *         status
	 */
	public static List<UserStory> getEventStories(long eventId, String status) {
		List<UserStory> stories = new ArrayList<UserStory>();

		Event event = Event.findById(eventId);
		List<Task> tasks = new ArrayList<Task>();
		tasks.addAll(event.tasks);
		for (int i = 0; i < tasks.size(); i++) {
			if (!(tasks.get(i).userStory == null)) {
				UserStory story = tasks.get(i).userStory;
				if (story.status.equals(status))
					if (!stories.contains(story))
						stories.add(story);
			}
		}

		return stories;

	}

	/**
	 * Returns all the tasks with a certain status in an event
	 * 
	 * @param eventId
	 *            the event id
	 * @param status
	 *            the status of the Task
	 * @return List <Task> a list of tasks in this event with this status
	 */
	public static List<Task> getEventTasks(long eventId, String status) {
		Event event = Event.findById(eventId);
		List<Task> tasks = event.getEventTasks();
		for (int i = 0; i < tasks.size();) {
			if (!tasks.get(i).status.status.equals(status)) {
				tasks.remove(i);
			} else
				i++;
		}

		return tasks;
	}

	/**
	 * Calls render to show all sprints in a project
	 * 
	 * @param projectId
	 *            the ID of the project
	 * 
	 */
	public static void showSprints(long projectId) {
		Project project = Project.findById(projectId);
		EventType type = EventType.find("byType", "Sprint").first();
		List<Event> sprints = Event.find("byProject_idAndType_id", projectId,
				type.getEntityId()).fetch();
		render(project, sprints);
	}

	/**
	 * Calls render to show the required sprint,
	 * 
	 * @param projectId
	 *            the ID of the project
	 * @param sprintId
	 *            the ID of the sprint
	 * 
	 */
	public static void editSprintPage(long projectId, long sprintId) {
		Project project = Project.findById(projectId);
		Event sprint = Event.findById(sprintId);
		render(project, sprint);
	}

	/**
	 * Edits a sprint's start and end date
	 * 
	 * @param projectId
	 *            the ID of the project to which this sprint is added
	 * @param sprintId
	 *            the ID of the sprint
	 * @param startDate
	 *            the startDate
	 * @param endDate
	 *            the endDate
	 */
	public static void editSprint(long projectId, long sprintId, String name,
			String description, String startDate, String endDate) {
		Event sprint = Event.findById(sprintId);
		String[] selectedStartDate = startDate.split("-");
		if (isValidDate(selectedStartDate)) {
			GregorianCalendar sDate = new GregorianCalendar(Integer
					.parseInt(selectedStartDate[2]), Integer
					.parseInt(selectedStartDate[1]) - 1, Integer
					.parseInt(selectedStartDate[0]));
			if (name.trim().isEmpty()) {
				flash.error("Sprint name can not be empty");
				createSprintForm(projectId);
			}
			sprint.name = name;
			sprint.description = description;
			String[] selectedEndDate = endDate.split("-");
			if (isValidDate(selectedEndDate)) {
				GregorianCalendar eDate = new GregorianCalendar(Integer
						.parseInt(selectedEndDate[2]), Integer
						.parseInt(selectedEndDate[1]) - 1, Integer
						.parseInt(selectedEndDate[0]));
				if (sDate.before(eDate)) {
					sprint.startDate = sDate;
					sprint.endDate = eDate;
					sprint.duration = new GregorianCalendar(Integer
							.parseInt(selectedEndDate[2]), Integer
							.parseInt(selectedEndDate[1]) - 1, Integer
							.parseInt(selectedEndDate[0]));
					sprint.duration.add(Calendar.YEAR, Integer
							.parseInt(selectedStartDate[2])
							* -1);
					sprint.duration.add(Calendar.MONTH, Integer
							.parseInt(selectedStartDate[1])
							* -1);
					sprint.duration.add(Calendar.DATE, Integer
							.parseInt(selectedStartDate[0])
							* -1);
					sprint.save();
					flash.success("Dates Edited!");
					showSprints(projectId);
				} else {
					flash.error("End Date is before Start Date");
					editSprintPage(projectId, sprintId);
				}
			} else {
				flash.error("Invalid End Date");
				editSprintPage(projectId, sprintId);
			}
		} else {
			flash.error("Invalid Start Date");
			editSprintPage(projectId, sprintId);
		}
	}

	/**
	 * 
	 * @param eventID
	 *            the sprint id
	 *@return boolean (true if today is in the sprint period this method is
	 *         used when anyone clicks to view the burnDown Chart but the sprint
	 *         didn't begin yet)
	 */
	public static boolean sprintInProgress(final long eventID) {

		Event event = Event.findById(eventID);
		Calendar date = Calendar.getInstance();
		if (date.compareTo(event.startDate) >= 0
				&& date.compareTo(event.endDate) <= 0) {
			return true;
		}
		return false;
	}

	/**
	 * The page that displays the list of events of the given project
	 * 
	 * @author Loai_Ghoraba
	 * @param projectId
	 *            the project
	 */
	public static void showProjectEvents(long projectId) {
		Project project = Project.findById(projectId);
		List<Event> allEvents = project.events;
		List<Event> events = new LinkedList<Event>();
		EventType defaultType = EventType.find("byType", "Default").first();
		EventType sprint = EventType.find("byType", "Sprint").first();
		// Get events that are not sprints neither the default one
		for (Event event : allEvents)
			if (event.type != defaultType && event.type != sprint
					&& event.status == true)
				events.add(event);
		render("Events/showEvents.html", events, project);
	}

	/**
	 * Retrieve all events in a project
	 * 
	 * @param project
	 *            the project
	 * @return all events in the project
	 */
	public static List<Event> getAllProjectEvents(Project project) {
		// Get sprints events
		List<Event> events = Event.find(
				"select e from Event e where e.sprint.project=?", project)
				.fetch();
		// Get evens related to the project directly
		List<Event> remainingEvents = Event
				.find(
						"select e from Event e where e.project=? and e.type.type!='Default' and e.type.type!='Sprint'",
						project).fetch();
		events.addAll(remainingEvents);
		return events;
	}

	/**
	 * The page that displays the list of events of the given meeting
	 * 
	 * @author Loai_Ghoraba
	 * @param sprintId
	 *            the sprint
	 */
	public static void showSprintEvents(long sprintId) {
		Event sprint = Event.findById(sprintId);
		List<Event> events = Event.find(
				"select e from Event e where e.sprint=? and e.status=?",
				sprint, true).fetch();
		render("Events/showEvents.html", sprint, events);
	}

	/**
	 * The page that shows the event
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the event to show
	 */
	public static void showEvent(long eventId) {
		Event event = Event.findById(eventId);
		if (event == null)
			forbidden("No such event exist");
		EventType sprintType = EventType.find("byType", "Sprint").first();
		if (event.type == sprintType)
			showSprint(eventId);
		List<Task> tasks = event.getEventTasks();
		List<UserStory> stories = getEventUserStories(event);
		List<User> users = event.getUsers();
		List<Note> noteassociated = Notes.getNotesByEventID(eventId);
		render(event, tasks, stories, users, noteassociated);
	}

	/**
	 * The page that shows the sprint
	 * 
	 * @param sprintId
	 *            the sprint to show
	 */
	public static void showSprint(long sprintId) {
		Event sprint = Event.findById(sprintId);
		List<Component> components = new LinkedList();
		components = sprint.project.components;
		for (int i = 0; i < components.size(); i++)
			if (components.get(i).name.equals("Default component")) {
				components.remove(i);
				break;
			}

//		List<Snapshot> snapShots = Snapshot.find(
//				"select c from Snapshot c where c.event=?", sprint).fetch();
		render(sprint, components);
	}

	/**
	 * The page that shows the form to associate user stories to an event
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the event to be associated to
	 */
	public static void associateStoriesPage(long eventId) {
		Event event = Event.findById(eventId);
		if (event == null || (event.type.type.equals("Sprint"))
				|| (event.type.type.equals("Default")))
			forbidden("No such event exist");
		Security.checkAccess("associate tasks to event", eventId, Event.class
				.getName());
		// Filter results
		Set<UserStory> temp = new HashSet<UserStory>();
		List<UserStory> newStories = Projects
				.getAllProjectStories(event.project);
		temp.addAll(newStories);
		newStories = new LinkedList<UserStory>();
		newStories.addAll(temp);

		List<UserStory> oldStories = getEventUserStories(event);
		newStories.removeAll(oldStories);
		render(event, newStories, oldStories);
	}

	/**
	 * calls <code> associateStories</code>
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the event id to be associated with
	 * @param storiesIds
	 *            the list of tasks to be associated
	 * 
	 */
	public static void associateStoriesToEvent(long eventId, long[] storiesIds) {
		Event event = Event.findById(eventId);
		if (event == null)
			forbidden("No such event exist");
		Security.checkAccess("associate tasks to event", eventId, Event.class
				.getName());
		// If no story is selected
		associateStories(event, storiesIds);
		flash.success("Stories associted successfully ");
		// Log and notify
		String msg = "User stories associated to event " + event.name
				+ " in project " + event.project.name + " are :\n\n";
		for (UserStory story : getEventUserStories(event))
			msg += story.story + "\n\n";
		List<User> users = EventUser.find(
				"select eu.user from EventUser eu where eu.event=?", event)
				.fetch();
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);
		if (!users.contains(user))
			users.add(user);
		for (User us : users)
			Mails.notify(us, "User Stories associated to event " + event.name,
					msg, "/events/showEvent?eventId=" + event.getEntityId());
		Notifications.notifyAllUsers(users, "User Stories associated to event",
				"Stories associatd to event " + event.name + ": " + msg);
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"stories associated to project  " + event.project.name
						+ " :\nmsg", (Long) event.project.getEntityId(), "")
				.save();
		showEvent(eventId);
	}

	/**
	 * Does the actual association of the user stories to the event
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event to be associated with
	 * @param storiesIds
	 *            the list of tasks to be associated
	 * @return true to test it
	 * 
	 */
	public static boolean associateStories(Event event, long[] storiesIds) {
		List<UserStory> stories = Projects.getAllProjectStories(event.project);
		// If he tries to associate with sprint
		if (event.type.type.equals("Sprint")
				|| event.type.type.equals("Default"))
			forbidden();
		List<UserStory> oldStories = getEventUserStories(event);
		List<UserStory> newStories = new LinkedList<UserStory>();
		// Check that there are stories selected
		if (storiesIds != null)
			for (long id : storiesIds) {
				UserStory story = UserStory.findById(id);
				// If he hack to associate stories from other projects
				if (!stories.contains(story))
					forbidden();
				newStories.add(story);
				// List<UserStory> stories=event.getUserStories();
				// if(!stories.contains(story))
				// event.associateUserStory(story);
			}
		// Associate new stories
		List<UserStory> toBeAssociated = new LinkedList<UserStory>();
		toBeAssociated.addAll(newStories);
		toBeAssociated.removeAll(oldStories);
		for (UserStory story : toBeAssociated)
			associateUserStory(event, story);
		// Remove stories
		List<UserStory> toBeRemoved = new LinkedList<UserStory>();
		toBeRemoved.addAll(oldStories);
		toBeRemoved.removeAll(newStories);
		for (UserStory story : toBeRemoved)
			unAssociateUserStory(event, story);

		event.save();

		return true;
	}

	/**
	 * The page that shows the form to associate tasks to an event
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the event to be associated to
	 */
	public static void associateTasksPage(long eventId) {
		Event event = Event.findById(eventId);
		if (event == null || (event.type.type.equals("Sprint"))
				|| (event.type.type.equals("Default")))
			forbidden("No such event exist");
		Security.checkAccess("associate tasks to event", eventId, Event.class
				.getName());

		Project project = event.project;
		List<Task> newTasks = project.getAllProjectTasks();
		List<Task> oldTasks = event.getEventTasks();
		newTasks.removeAll(oldTasks);
		render(event, newTasks, oldTasks);
	}

	/**
	 * calls <code>associateTasks</code>
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the event id to be associated with
	 * @param tasksIds
	 *            the list of tasks to be associated
	 * 
	 */
	public static void associateTasksToEvent(long eventId, long[] tasksIds) {
		Event event = Event.findById(eventId);
		System.out.println(" heeeeeeeey !!" + tasksIds);
		if (tasksIds != null)
			for (long id : tasksIds)
				System.out.println(id);
		if (event == null)
			forbidden("No such event exist");
		Security.checkAccess("associate tasks to event", eventId, Event.class
				.getName());
		associateTasks(event, tasksIds);
		flash.success("Tasks associted successfully ");
		String msg = "Tasks associated to event " + event.name + " in project "
				+ event.project.name + " are :\n\n";
		for (Task task : event.getEventTasks())
			msg += task.description + "\n\n";
		List<User> users = EventUser.find(
				"select eu.user from EventUser eu where eu.event=?", event)
				.fetch();
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);
		if (!users.contains(user))
			users.add(user);
		for (User us : users)
			Mails.notify(us, "Tasks associated to event " + event.name, msg,
					"/events/showEvent?eventId=" + event.getEntityId());
		Notifications.notifyAllUsers(users, "Tasks associated to event",
				"Task associatd to event " + event.name + ": " + msg);
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"tasks associated to project  " + event.project.name
						+ " :\nmsg", (Long) event.project.getEntityId(), "")
				.save();
		showEvent(eventId);
	}

	/**
	 * Does the actual association of tasks to event
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event the event id to be associated with
	 * @param tasksIds
	 *            the list of tasks to be associated
	 * @return true to be able to test it
	 * 
	 */
	public static boolean associateTasks(Event event, long[] tasksIds) {
		if (event.type.type.equals("Sprint")
				|| event.type.type.equals("Default"))
			forbidden("Inavlid event type");
		List<Task> allTasks = event.project.getAllProjectTasks();
		List<Task> oldTasks = event.getEventTasks();
		List<Task> newTasks = new LinkedList<Task>();
		// Check that there are tasks selected
		if (tasksIds != null)
			for (long id : tasksIds) {
				Task task = Task.findById(id);
				// If he hack to associate tasks from other projects
				if (!allTasks.contains(task)) {
					forbidden("Non consistent tasks");
				}
				newTasks.add(task);
			}
		// Associate new tasks
		List<Task> toBeAssociated = new LinkedList<Task>();
		toBeAssociated.addAll(newTasks);
		toBeAssociated.removeAll(oldTasks);
		for (Task task : toBeAssociated)
			associateTask(event, task);
		// Remove tasks
		List<Task> toBeRemoved = new LinkedList<Task>();
		toBeRemoved.addAll(oldTasks);
		toBeRemoved.removeAll(newTasks);
		for (Task task : toBeRemoved)
			unAssociateTask(event, task);
		event.save();
		return true;
	}

	/**
	 * Associate a developer to an event
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param userId
	 *            the id of the user
	 * @author Mohammed Mosaad
	 */
	public static void associateDeveloper(long eventId, long userId) {

		Event event = Event.findById(eventId);
		User user = User.findById(userId);
		if ((event.type.type.equals("Sprint"))
				|| (!Users.getDeveloperInProject(event.project.id).contains(
						user)) || (user == null) || event == null)
			forbidden();

		Security.checkAccess("associate developer to event", eventId,
				Event.class.getName());
		EventUser e2 = EventUser.find(
				"select e from EventUser e where e.event=? and e.user=?",
				event, user).first();
		if (e2 != null)
			return;
		List<EventUser> userEvents = EventUser.find(
				"select e from EventUser e where e.user=?", user).fetch();

		if (!userFree(userEvents, event)) {
			flash.error("User is attending another meeting in the same time");
			developerAssociation(event.id);
		}

		EventUser e = new EventUser(user, event).save();
		event.eventAttendees.add(e);
		user.eventAttendees.add(e);
		event.save();
		user.save();
		new Notification(userId, event.name + " attendance",
				"You are required to attend " + event.name).save();
		flash.success(user.firstName + user.middleName + user.lastName
				+ " has been associated");
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"user associated to event  " + event.name + " :\nmsg",
				(Long) event.project.getEntityId(), "").save();
		developerAssociation(eventId);
	}

	/**
	 * checks if the list of events have conflicting time with a certain event
	 * 
	 * @param list
	 *            list of events
	 * @param event
	 *            event that wants to be checked
	 * @return
	 */
	public static boolean userFree(List<EventUser> list, Event event) {

		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).event.startDate.equals(event.startDate)
					|| list.get(i).event.endDate.equals(event.endDate))
				return false;
			if (list.get(i).event.endDate.after(event.startDate)
					&& list.get(i).event.endDate.before(event.startDate))
				return false;
			if (list.get(i).event.startDate.after(event.startDate)
					&& list.get(i).event.startDate.before(event.endDate))
				return false;
		}
		return true;
	}

	/**
	 * Page for Association of a developer or all developers of a component to
	 * an event
	 * 
	 * @param projectId
	 *            the id of the project that the event and user are in
	 * @param eventId
	 *            the id of the event that user will get associated to
	 * @author Mohammed Mosaad
	 */

	public static void developerAssociation(long eventId) {

		Event event = Event.findById(eventId);

		if ((event == null) || (event.type.type.equals("Sprint"))
				|| (event.type.type.equals("Default")))
			forbidden("NO SUCH EVENT EXISTS");
		Security.checkAccess("associate developer to event", eventId,
				Event.class.getName());
		Project project = event.project;
		List<User> list = Users.getDeveloperInProject(project.id);
		List<User> associated = new LinkedList<User>();
		List<User> notassociated = new LinkedList<User>();
		for (int i = 0; i < list.size(); i++) {
			EventUser e = EventUser.find(
					"select e from EventUser e where e.event=? and e.user=?",
					event, list.get(i)).first();
			if (e != null)
				notassociated.add(list.get(i));
			else
				associated.add(list.get(i));
		}

		List<Component> components = project.components;
		List<Component> associatedComp = new LinkedList<Component>();
		List<Component> notassociatedComp = new LinkedList<Component>();
		for (int j = 0; j < components.size(); j++) {
			if (allAssociated(eventId, components.get(j).id))
				notassociatedComp.add(components.get(j));
			else
				associatedComp.add(components.get(j));
		}
		render(associated, notassociated, event, associatedComp,
				notassociatedComp);
	}

	/**
	 * Checks if all members of a certain component are assoicated or not
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param componentId
	 *            the id of the component
	 * @return
	 * 
	 * @author Mohammed Mosaad
	 */
	public static boolean allAssociated(long eventId, long componentId) {

		Event event = Event.findById(eventId);
		Component comp = Component.findById(componentId);
		if (comp.user_components.isEmpty())
			return true;
		for (int i = 0; i < comp.user_components.size(); i++) {
			if (EventUser.find(
					"select e from EventUser e where e.event=? and e.user=?",
					event, comp.user_components.get(i).user).first() == null)
				return false;

		}
		return true;
	}

	/**
	 * Remove association of a user from an event
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param userId
	 *            the id of the user
	 * 
	 * @author Mohammed Mosaad
	 */
	public static void unAssociateDeveloper(long eventId, long userId) {

		Event event = Event.findById(eventId);
		User user = User.findById(userId);
		if ((event.type.type.equals("Sprint"))
				|| (!Users.getDeveloperInProject(event.project.id).contains(
						user)) || (event == null) || (user == null))
			forbidden();

		Security.checkAccess("associate developer to event", eventId,
				Event.class.getName());

		EventUser e = EventUser.find(
				"select e from EventUser e where e.event=? and e.user=?",
				event, user).first();
		if (e == null)
			return;
		event.eventAttendees.remove(e);
		user.eventAttendees.remove(e);
		user.save();
		event.save();
		e.delete();
		new Notification(userId, event.name + " attendance",
				"You are no longer required to attend " + event.name).save();

		flash.success(user.firstName + user.middleName + user.lastName
				+ " has been unassociated");
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"user Unassociated to event  " + event.name + " :\nmsg",
				(Long) event.project.getEntityId(), "").save();
		developerAssociation(eventId);
	}

	/**
	 * Associate all members of a component to a specific event
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param componentId
	 *            the id of the component
	 */
	public static void associateComponent(long eventId, long componentId) {

		Event event = Event.findById(eventId);
		Component comp = Component.findById(componentId);
		if (event.type.type.equals("Sprint")
				|| (event.project.id != comp.project.id) || (event == null)
				|| (comp == null))
			forbidden();

		Security.checkAccess("associate developer to event", eventId,
				Event.class.getName());

		EventUser e2;
		List<EventUser> userEvents;
		for (int i = 0; i < comp.user_components.size(); i++) {
			e2 = EventUser.find(
					"select e from EventUser e where e.event=? and e.user=?",
					event, comp.user_components.get(i).user).first();
			if (e2 != null)
				break;
			userEvents = EventUser.find(
					"select e from EventUser e where e.user=?",
					comp.user_components.get(i).user).fetch();
			if (!userFree(userEvents, event)) {
				flash
						.error("One of the members is attending another meeting in the same time operation stopped");
				developerAssociation(event.id);
			}
			EventUser e = new EventUser(comp.user_components.get(i).user, event)
					.save();
			event.eventAttendees.add(e);
			comp.user_components.get(i).user.eventAttendees.add(e);
			event.save();
			comp.user_components.get(i).user.save();
			new Notification(comp.user_components.get(i).user.id, event.name
					+ " attendance", "You are required to attend " + event.name)
					.save();
			new Log(comp.user_components.get(i).user.id, (Long) event
					.getEntityId(), Event.class.getName(),
					"user associated to event  " + event.name + " :\nmsg",
					(Long) event.project.getEntityId(), "").save();

		}
		flash.success("All memebers of " + comp.name + " have been assoicated");

		developerAssociation(eventId);
	}

	/**
	 * Unassociate the members of a whole component to a certain event
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param componentId
	 *            the id of the component
	 */
	public static void unAssociateComponent(long eventId, long componentId) {

		Event event = Event.findById(eventId);
		Component comp = Component.findById(componentId);
		if (event.type.type.equals("Sprint")
				|| (event.project.getEntityId() != comp.project.getEntityId())
				|| (event == null) || (comp == null))
			forbidden();

		Security.checkAccess("associate developer to event", eventId,
				Event.class.getName());

		EventUser e2;
		for (int i = 0; i < comp.user_components.size(); i++) {
			e2 = EventUser.find(
					"select e from EventUser e where e.event=? and e.user=?",
					event, comp.user_components.get(i).user).first();

			event.eventAttendees.remove(e2);
			comp.user_components.get(i).user.eventAttendees.remove(e2);
			event.save();
			comp.user_components.get(i).user.save();
			e2.delete();
			new Notification(comp.user_components.get(i).user.id, event.name
					+ " attendance", "You are no longer required to attend "
					+ event.name).save();
			new Log(comp.user_components.get(i).user.id, (Long) event
					.getEntityId(), Event.class.getName(),
					"user associated to event  " + event.name + " :\nmsg",
					(Long) event.project.getEntityId(), "").save();
		}
		event.save();
		flash.success("All memebers of " + comp.name
				+ " have been unassoicated");
		developerAssociation(eventId);

	}

	/**
	 * Associates a task to this event, we created this method instead of using
	 * tasks.add(task) as we need to check for other things
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event to associate with
	 * @param task
	 *            the task to associate
	 * @return true to use it in the unit test
	 * 
	 */
	public static boolean associateTask(Event event, Task task) {
		if (event.tasks.contains(task))
			return true;
		event.tasks.add(task);
		task.events.add(event);
		task.save();
		// See if the task is associated to the default event, then remove it
		// form there
		Event defaultEvent = null;
		EventType defaultType = EventType.find("byType", "Default").first();
		for (Event ev : task.events)
			if (ev.type == defaultType) {
				defaultEvent = ev;
				break;
			}
		// Remove the task from the default event
		if (defaultEvent != null && defaultEvent != event) {
			defaultEvent.tasks.remove(task);
			task.events.remove(defaultEvent);
			task.save();
			defaultEvent.save();
		}
		return true;
	}

	/**
	 * Removes a task form this event ,instead of using task.remove(task), as
	 * there are other things we need to check for
	 * 
	 * @author Loai_Ghoraba
	 * @param task
	 *            the task to remove
	 * @param event
	 *            the event to associate to
	 * @return returns true just to use it in the unit test
	 */
	public static boolean unAssociateTask(Event event, Task task) {
		event.removeTask(task);
		// Remove the user story from the event
		if (task.userStory != null) {
			event.userStories.remove(task.userStory);
			task.userStory.events.remove(event);
		}
		EventType defaultType = EventType.find("byType", "Default").first();
		if (event.type != defaultType && task.events.size() == 0)// We have to
		// associate it to
		// the default event
		{
			Project p = event.project;
			Event defaultEvent = Event.find(
					"select e from Event e where e.project=? and e.type=?", p,
					defaultType).first();
			if (defaultEvent != null) {
				defaultEvent.tasks.add(task);
				task.events.add(defaultEvent);
				task.save();
				defaultEvent.save();
			}
		}
		return true;
	}

	/**
	 * 
	 * Associates the user story <code>story</code> to this event
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event to associate with
	 * @param story
	 *            the user story to be associated
	 * @return return true just to allow calling it in the test
	 */
	public static boolean associateUserStory(Event event, UserStory story) {
		List<UserStory> stories = event.userStories;
		if (stories.contains(story))
			return true;
		stories.add(story);
		story.events.add(event);
		event.save();
		return true;
	}

	/**
	 * Removes a user story from this event
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event to associate with
	 * @param story
	 *            the story to remove
	 * @return true to allow it to be called from the test
	 */
	public static boolean unAssociateUserStory(Event event, UserStory story) {
		List<UserStory> stories = event.userStories;
		stories.remove(story);
		story.events.remove(event);
		List<Task> toBeRemoved = story.tasks;
		for (Task task : toBeRemoved)
			unAssociateTask(event, task);
		event.save();
		return true;
	}

	/**
	 * Retrieve all sprints in the given project
	 * 
	 * @param project
	 *            the project
	 * @return all sprints in the given project
	 */
	static List<Event> getProjectSprints(Project project) {
		EventType sprintType = EventType.find("byType", "Sprint").first();
		List<Event> sprints = Event.find("byProjectAndType", project,
				sprintType).fetch();
		return sprints;
	}

	/**
	 * returns the sprint upcoming or in progress that the task is associated
	 * with and returns null otherwise
	 * 
	 * @author Rana Ashraf
	 * @param task
	 * @return Event
	 */
	public static Event getTaskSprintCurrent(Task task) {
		if (task.events != null) {
			for (int i = 0; i < task.events.size(); i++) {
				if (task.events.get(i).type != null) {
					if (task.events.get(i).type.type.equals("Sprint")) {
						if (notPastEvent((Long) task.events.get(i)
								.getEntityId()))
							return task.events.get(i);
					}
				}
			}
		}

		return null;
	}

	/**
	 * returns a list of all events -excluding sprints- that are not over yet
	 * that are associated to a specific task. returns null otherwise
	 * 
	 * @author Rana Ashraf
	 * @param task
	 * @return List<Event>
	 */
	public static List<Event> getTaskEventsNotPast(Task task) {
		List<Event> result = new LinkedList<Event>();
		List<Event> events = task.getTaskEvents();
		for (int i = 0; i < events.size(); i++) {
			if (events.get(i).type != null) {
				if (!events.get(i).type.type.equals("Sprint")) {
					if (notPastEvent((Long) events.get(i).getEntityId()))
						result.add(events.get(i));
				}
			}
		}

		if (result.isEmpty())
			return null;
		return result;
	}

	/**
	 * Deletes an event
	 * 
	 * @author Loai_Ghoraba
	 * @param eventId
	 *            the if of the event to delete
	 */
	public static void deleteEvent(long eventId) {
		Security.checkAccess("Delete an event", eventId, Event.class.getName());
		Event event = Event.findById(eventId);
		// He cannot delete the default one nor a sprint
		if (event.type.type == "Sprint" || event.type.type == "Default")
			forbidden();
		// Get all users in the event and notify them
		List<User> users = EventUser.find(
				"select eu.user from EventUser eu where eu.event=?", event)
				.fetch();
		long projectId = (Long) event.project.getEntityId();
		event.delete();
		flash.success("Event " + event.name + " is deleted succesfully");
		// Notify
		for (User us : users)
			Mails.notify(us, "Event deleted " + event.name, "Event "
					+ event.name + " is deleted", "");
		Notifications.notifyAllUsers(users, "Event deleted", "Event "
				+ event.name + " is deleted");
		long userId = Long.parseLong(session.get("userId"));
		// Log
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"Event " + event.name + " is deleted", projectId, "").save();
		Projects.showProject(projectId);
	}

	/**
	 * Associate a note to a event & sends a notification to every user
	 * attending the event the a note has been associated
	 * 
	 * @param eventId
	 *            the id of the event
	 * @param notelist
	 *            the list of notes
	 * @author Adam El Shafei
	 */
	public static void noteAssociate(long eventId, long[] notelistIds) {
		Event event = Event.findById(eventId);
		if (event == null)
			return;
		Security.checkAccess("associate note to event", eventId, Event.class
				.getName());
		long projectId = event.project.id;
		if (notelistIds == null) {
			flash.error("You must select a note");
			showEvent(eventId);
			// Event defaultEvent=Events.getDefaultEvent(project);
			// defaultEvent.notes.add(note);
			// defaultEvent.save();
		} else {
			for (long id : notelistIds) {
				Note notes = Note.findById(id);
				event.notes.add(notes);
				event.save();
			}
		}
		flash.success("Note associated successfully");
		showProjectEvents(projectId);
		List<User> users = EventUser.find(
				"select eu.user from EventUser eu where eu.event=?", event)
				.fetch();
		long userId = Long.parseLong(session.get("userId"));
		User user = User.findById(userId);
		if (!users.contains(user))
			users.add(user);
		Notifications.notifyAllUsers(users, "Note associated to event",
				"Note associatd to event " + event.name);
		new Log(userId, (Long) event.getEntityId(), Event.class.getName(),
				"note associated to event  " + event.name + " :\nmsg",
				(Long) event.project.getEntityId(), "").save();
	}

	/**
	 *Page for Association of a note to an event. Renders list of notes
	 * 
	 * @param eventId
	 *            the id of the event
	 * 
	 * @author Adam El Shafei
	 */
	public static void associateNote(long eventId) {
		Event event = Event.findById(eventId);
		if ((event == null) || (event.type.type.equals("Sprint"))
				|| (event.type.type.equals("Default")))
			forbidden();
		Project project = event.project;
		List<Event> eventlist = project.events;
		List<Note> unassociatednote = new LinkedList<Note>();
		for (int i = 0; i < eventlist.size(); i++) {
			for (int j = 0; j < eventlist.get(i).notes.size(); j++) {
				if (!event.notes.contains(eventlist.get(i).notes.get(j)))
					unassociatednote.add(eventlist.get(i).notes.get(j));
			}
		}
		List<Note> notelist = Notes.getNotesByEventID(eventId);
		render(event, notelist, unassociatednote);
	}

	/**
	 * Checks that the given date (represented by an array of Strings) is a
	 * valid date
	 * 
	 * @param date
	 *            the date to check
	 */
	public static boolean isValidDate(String[] date) {
		if (date.length != 3)
			return false;
		try {
			GregorianCalendar gc = new GregorianCalendar();
			gc.setLenient(false);
			gc.set(GregorianCalendar.YEAR, Integer.parseInt(date[2]));
			gc.set(GregorianCalendar.MONTH, Integer.parseInt(date[1]));
			gc.set(GregorianCalendar.DATE, Integer.parseInt(date[0]));

			gc.getTime();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Returns a list of user stories whose tasks are all present in the given
	 * list of tasks
	 * 
	 * @author Loai_Ghoraba
	 * @param tasks
	 *            the list of tasks
	 * @return a list of user stories whose tasks are all present in the list of
	 *         tasks
	 */
	public static List<UserStory> getCompleteUserStories(List<Task> tasks) {
		Set<UserStory> stories = new HashSet<UserStory>();
		Set<UserStory> temp = new HashSet<UserStory>();
		// Get each user story if any task of it is in the list
		for (Task task : tasks) {
			if (task.userStory != null)
				stories.add(task.userStory);
		}
		temp.addAll(stories);
		// Filter the results
		for (UserStory story : temp)
			for (Task task : story.tasks)
				if (!tasks.contains(task)) {
					stories.remove(story);
					break;
				}
		List<UserStory> result = new LinkedList<UserStory>();
		result.addAll(stories);
		return result;
	}

	/**
	 * Returns the default event associated with a specific project
	 * 
	 * @author Rana Ashraf
	 * @param project
	 * @return Event
	 */
	public static Event getDefaultEvent(Project project) {
		EventType eventType = EventType.find("byType", "Default").first();
		Event defaultEvent = Event.find(
				"select e from Event e where e.project=? and e.type=? ",
				project, eventType).first();
		return defaultEvent;
	}

	/**
	 * Returns a list of all associated user stories with this event
	 * 
	 * @author Loai_Ghoraba
	 * @param event
	 *            the event
	 * @return list of all user stories in the event
	 * 
	 */
	public static List<UserStory> getEventUserStories(Event event) {
		List<Task> tasks = event.tasks;
		Set<UserStory> stories = new HashSet<UserStory>();
		Set<UserStory> temp = new HashSet<UserStory>();
		// Get each user story if any task of it is in the list
		for (Task task : tasks) {
			if (task.userStory != null)
				stories.add(task.userStory);
		}
		temp.addAll(stories);
		// Filter the results
		for (UserStory story : temp)
			for (Task task : story.tasks)
				if (!tasks.contains(task)) {
					stories.remove(story);
					break;
				}
		stories.addAll(event.userStories);
		List<UserStory> result = new LinkedList<UserStory>();
		result.addAll(stories);
		return result;
	}

	/**
	 * Returns all tasks in this event which have no user stories
	 * 
	 * @param event
	 *            the event
	 * @return all tasks in this event which have no user stories
	 */
	public static List<Task> getEventTasksNotHaveUserStory(Event event) {
		List<Task> tasks = event.getEventTasks();
		List<Task> result = new LinkedList<Task>();
		for (Task task : tasks)
			if (task.userStory == null)
				result.add(task);
		return result;
	}
}
